﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Nes.Core.APUS
{
    /// <summary>
    /// 三角波
    /// </summary>
    public class Triangle
    {
        public Int32 LengthCounter { get; internal set; }

        private Boolean LinearCounterReloadFlag;

        private Boolean _enable;
        public bool Enable
        {
            get
            {
                return _enable;
            }
            set
            {
                _enable = value;
                if (!Enable)
                {
                    LengthCounter = 0;
                }
            }
        }
        public Int32 Volume { get; internal set; }
        public Int32 Timer { get; private set; }
        private Int32 InternalTimer;
        private Boolean LengthCounterHalt;
        private Int32 LinearCounterLoad;
        private Int32 LinearCounterValue;
        private Int32 Counter;

        internal void Clock()
        {
            if (!Enable)
            {
                return;
            }
            if (InternalTimer == 0)
            {
                InternalTimer = Timer;
                Step();
            }
            else
            {
                InternalTimer--;
            }
        }

        private void Step()
        {
            Counter++;
            if(!Enable || LengthCounter == 0 || LinearCounterValue == 0)
            {
                Counter--;
            }
            Volume = CommonProp.TriangleVolumeTable[Counter & 0x1F];
        }

        internal void ProcessLengthCounter()
        {
            if(!LengthCounterHalt && LengthCounter > 0)
            {
                LengthCounter--;
            }
        }

        internal void ProcessLinearlope()
        {
            if (LinearCounterReloadFlag)
            {
                LinearCounterValue = LinearCounterLoad;
            }
            else if(LinearCounterValue > 0)
            {
                LinearCounterValue--;
            }
            else if(LengthCounterHalt)
            {
                LinearCounterReloadFlag = false;
            }
        }

        internal void Write(Int32 addr, Byte data)
        {
            switch (addr)
            {
                case 0: // CRRR RRRR
                    LengthCounterHalt = (data & 0b1000_0000) > 0;
                    LinearCounterLoad = (data & 0b0111_1111);
                    break;
                case 1: // Unused
                    break;
                case 2: // TTTT TTTT	Timer low (T)
                    Timer = ((Timer & 0xFF00) | data);
                    break;
                case 3: // LLLL LTTT	Length counter load (L), timer high (T), set linear counter reload flag
                    Timer = ((Timer & 0x00FF) | (data & 0b0000_0111) << 8);
                    LengthCounter = CommonProp.LengthTable[data >> 3];
                    LinearCounterReloadFlag = true;
                    InternalTimer = 0;
                    break;
            }
        }
    }
}
